package com.example.prom.aspect;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 日志切面
 */

@Component  //标识为一个组件
@Aspect     //标识为一个切面
@Order(2)   // 切面类执行的优先级，即执行顺序，order后数字越小，优先级越高
public class LoggingAspect {

    /**
     * 声明切入点表达式
     */
    @Pointcut("execution(* com.example.prom.ok.y2022.service.taxbit.*.*(..))")
    public void declarePointCut() {}

    /**
     * 前置通知: 在目标方法(连接点)执行之前执行.
     */
    @Before("declarePointCut()")
    public void  beforeMethod(JoinPoint joinPoint) {
        //获取方法的参数
        Object [] args = joinPoint.getArgs();
        //方法的名字
        String methodName = joinPoint.getSignature().getName();

        System.out.println("LoggingAspect==> The method "+methodName+" begin with "+ Arrays.asList(

        ));
    }

    /**
     * 后置通知: 在目标方法执行之后执行， 不管目标方法有没有抛出异常.  不能获取方法的结果
     *    * com.yw.spring.aspectJ.annotation.*.*(..)
     *    * : 任意修饰符 任意返回值
     *    * : 任意类
     *    * : 任意方法
     *    ..: 任意参数列表
     *
     * 连接点对象: JoinPoint
     */

    //@After("execution(* com.yw.spring.aspectJ.annotation.*.*(..))")
    @After("declarePointCut()")
    public void afterMethod(JoinPoint joinPoint) {
        //方法的名字
        String methodName = joinPoint.getSignature().getName();
        System.out.println("LoggingAspect==> The method " + methodName +" ends .");
    }

    /**
     * 返回通知: 在目标方法正常执行结束后执行.  可以获取到方法的返回值.
     *
     * 获取方法的返回值: 通过returning 来指定一个名字， 必须要与方法的一个形参名一致.
     */
    //@AfterReturning(value="execution(* com.yw.spring.aspectJ.annotation.*.*(..))",returning="result")
    @AfterReturning(value="declarePointCut()",returning="result")
    public void afterReturningMethod(JoinPoint joinPoint,Object result ) {
        //方法的名字
        String methodName = joinPoint.getSignature().getName();
        System.out.println("LoggingAspect==> The method " + methodName + " end with :" + result );
    }
    /**
     * 异常通知: 在目标方法抛出异常后执行.
     *
     * 获取方法的异常: 通过throwing来指定一个名字， 必须要与方法的一个形参名一致.
     *
     * 可以通过形参中异常的类型 来设置抛出指定异常才会执行异常通知.
     *
     */
    @AfterThrowing(value="declarePointCut()",throwing="ex")
    public void afterThrowingMethod(JoinPoint joinPoint,ArithmeticException ex ) {
        //方法的名字
        String methodName = joinPoint.getSignature().getName();

        System.out.println("LoggingAspect==> Thew method " + methodName + " occurs Exception: " +ex );
    }

    /**
     * 环绕通知: 环绕着目标方法执行. 可以理解是 前置 后置 返回  异常 通知的结合体，更像是动态代理的整个过程.
     */

//    @Pointcut("execution(* com.example.prom.ok.y2022.service.taxbit.*.*(..))")
//    public  Object  aroundMethod(ProceedingJoinPoint pjp) {
//        //执行目标方法
//        try {
//            //前置
//            Object result = pjp.proceed();
//            //返回
//            return result ;
//        } catch (Throwable e) {
//            //异常通知
//            e.printStackTrace();
//        }finally {
//            // 后置
//        }
//        return null;
//    }
}